package com.learn.boot.xss.filter;

import com.google.common.collect.Lists;
import com.learn.boot.xss.config.RequestProperties;
import com.learn.boot.xss.config.XssProperties;
import com.learn.boot.xss.servlet.XssHttpServletRequestWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.List;

/**
 * Request全局过滤
 * @author:         MI
 * @email:          448341911@qq.com
 * @createDate:     2023/11/12 21:26
 * @updateUser:     MI
 * @updateDate:     2023/11/12 21:26
 * @updateRemark:   修改内容
 * @version:        v1.0
 */
public class MateRequestFilter implements Filter {

    /**
     * 不拦截的地址
     */
    private List<String> excludedList = Lists.newArrayList();

    private XssProperties xssProperties;

    private RequestProperties requestProperties;

    public boolean enableSqlFilter = false;

    public MateRequestFilter() {
    }

    public void setEnableSqlFilter(boolean enableSqlFilter) {
        this.enableSqlFilter = enableSqlFilter;
    }

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    public MateRequestFilter(RequestProperties requestProperties,XssProperties xssProperties) {
        this.requestProperties = requestProperties;
        this.xssProperties = xssProperties;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        /*
         * 这里只处理了不拦截的url地址，如果想不拦截某个字段，比如富文本字段，
         * 需要自己在XssHttpServletRequestWrapper类中去添加逻辑
         */
        excludedList.add("/test/excluded1");
        excludedList.add("/test/excluded2");

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper(
                (HttpServletRequest) request);
        String path = xssRequest.getServletPath();
        // 跳过 Request 包装
        if (isExcluded(path)) {
            chain.doFilter(request, response);
        } else if (!xssProperties.getEnabled() || isXssSkip(path)) {
            //使用XSS过滤
            chain.doFilter(xssRequest, response);
        } else {
            // Xss Request 包装

            chain.doFilter(xssRequest, response);
        }
    }

    /**
     * 是否不拦截
     * @param url	请求地址
     * @return	true不拦截，false拦截
     */
    private boolean isExcluded(String url){
        if(StringUtils.isBlank(url)){
            return false;
        }

        for (String excluded : excludedList) {
            if(url.contains(excluded)){
                return true;
            }
        }
        return false;
    }




    private boolean isXssSkip(String path) {
        return xssProperties.getSkipUrl().stream().anyMatch(pattern -> antPathMatcher.match(pattern, path));
    }

    @Override
    public void destroy() {

    }
}
